package com.yanqu.road.server.manger.activity.climbtower;

import com.yanqu.road.dao.impl.activity.climbtower.ClimbTowerConfigDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.climbtower.*;
import com.yanqu.road.entity.activity.climbtower.enums.eClimbTowerCellType;
import com.yanqu.road.entity.activity.climbtower.enums.eClimbTowerEventType;
import com.yanqu.road.entity.enums.eActivityConfigType;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.logic.bussiness.player.ClimbTowerActivityBussiness;
import com.yanqu.road.pb.activity.ClimbTowerProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.climbtower.ClimbTowerModule;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.util.*;

public class ClimbTowerMgr extends TempMgr {

    static int DRAW_ELEMENT_NUM = 9;

    static ClimbTowerConfig config;

    static List<ClimbTowerProto.ClimbTowerBossRewardTemp> bossRewardTempList = new ArrayList<>();

    public static ActivityInfo getActivityInfo() {
        if(config == null) {
            return null;
        }
        return config.getActivityInfo();
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    public static void reloadActivityData() {
        getLogger().info("reload ClimbTower Activity start");
        ActivityInfo tempActivityInfo;
        List<ActivityInfo> openActivityInfoList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.ClimbTower.getValue());
        if (openActivityInfoList.isEmpty()) {
            getLogger().info("no ClimbTower Activity in show time");
            config = null;
        }else {
            List<ClimbTowerProto.ClimbTowerBossRewardTemp> bossRewardTemps = new ArrayList<>();
            tempActivityInfo = openActivityInfoList.get(0);
            int tmpActivityId = tempActivityInfo.getActivityId();

            ClimbTowerConfig configTemp  = new ClimbTowerConfig();
            configTemp.setActivityInfo(tempActivityInfo);

            //初始化配置
            //config配置
            Map<String, ActivityConfig> activityConfigMap = NormalActivityMgr.getActivityConfigMap(tmpActivityId);
            //先解析boss配置
            configTemp.setBossExParamList(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_TOWER_BOSS_EXPARAM.getName()).getValue(), "\\|"));

            List<ClimbTowerLevelInfo> levelInfoList = ClimbTowerActivityBussiness.getLevelInfoList(tmpActivityId);
            List<ClimbTowerTemplateInfo> templateInfoList = ClimbTowerActivityBussiness.getTemplateInfoList(tmpActivityId);
            List<ClimbTowerInfo> towerInfoList = new ClimbTowerConfigDaoImpl().getClimbTowerInfoList(tmpActivityId);
            configTemp.setTowerInfoList(towerInfoList);

            int totalCellNum = 0;  //总层数
            int bossTimes = 0;  //boss出现次数
            //临时
            //阶段翻转配置
            List<Integer> overturnList = new ArrayList<>();
            if(activityConfigMap.containsKey("EXCITINGTOWER_TOWER_MIRROR")){
                overturnList = StringUtils.stringToIntegerList(activityConfigMap.get("EXCITINGTOWER_TOWER_MIRROR").getValue(), "\\|");
            }
            //层类型翻转映射
            int[] cellTypeReverseList = new int[]{0, 1, 2, 4, 3, 5};
            for (int passIdIndex = 0; passIdIndex < levelInfoList.size(); passIdIndex++) {
                ClimbTowerLevelInfo levelInfo = levelInfoList.get(passIdIndex);
                if(levelInfo.getBossId() > 0){
                    bossTimes++;
                }
                ClimbTowerTemplateInfo templateInfo = configTemp.getClimbTowerTemplateInfo(templateInfoList, levelInfo.getTemplateId());
                if(templateInfo == null){
                    getLogger().info("ClimbTower Activity {} template {} not found", tmpActivityId, levelInfo.getId());
                    return;
                }
                levelInfo.setTemplateInfo(templateInfo);
                List<Integer> codeA = StringUtils.stringToIntegerList(templateInfo.getCodeA(), "\\|");
                if(templateInfo.getEventList().size() != codeA.size() || templateInfo.getPicList().size() != codeA.size()){
                    getLogger().info("ClimbTower Activity {} levelInfo {} config error", tmpActivityId, levelInfo.getId());
                    return;
                }
                //该层是否需要翻转
                boolean needOverTurn = false;
                if(overturnList.size() > passIdIndex && overturnList.get(passIdIndex) == 1){
                    needOverTurn = true;
                }
                if(needOverTurn){
                    List<Integer> tempCodeA = new ArrayList<>();
                    for (int i = 0; i < codeA.size(); i++) {
                        tempCodeA.add(cellTypeReverseList[codeA.get(i)]);
                    }
                    codeA = tempCodeA;
                }
                levelInfo.setCellTypeList(codeA);
                for (int cellIdx = 0; cellIdx < templateInfo.getEventList().size(); cellIdx++) {
                    String event = templateInfo.getEventList().get(cellIdx);
                    List<String> cellEventString = StringUtils.stringToStringList(event, ";");
                    if(needOverTurn){
                        Collections.reverse(cellEventString);
                    }
                    //每层事件个数校验
                    int cellType = levelInfo.getCellTypeList().get(cellIdx);
                    int eventNum = eClimbTowerCellType.getEventNum(cellType);
                    if(eventNum != cellEventString.size()){
                        getLogger().info("ClimbTower Activity {} levelInfo {}  template {} config event error", tmpActivityId, levelInfo.getId(), templateInfo.getId());
                        return;
                    }
                    //形象校验
                    String pic = templateInfo.getPicList().get(cellIdx);
                    List<Integer> eventPicList = StringUtils.stringToIntegerList(pic, ";");
                    if(eventNum > eventPicList.size()){
                        getLogger().info("ClimbTower Activity {} levelInfo {}  template {} config pic error", tmpActivityId, levelInfo.getId(), templateInfo.getId());
                        return;
                    }
                    if(needOverTurn){
                        Collections.reverse(eventPicList);
                    }
                    ClimbTowerCell cell = new ClimbTowerCell();
                    cell.setPassId(levelInfo.getId());
                    cell.setCellType(cellType);
                    cell.setCellNum(++totalCellNum);
                    ClimbTowerInfo towerInfo = configTemp.getClimbTowerInfo(cell.getCellNum());
                    for (int k = 0; k < cellEventString.size(); k++) {
                        String eventString = cellEventString.get(k);
                        List<String> eventConfig = StringUtils.stringToStringList(eventString, "=");
                        ClimbTowerCellEvent cellEvent = new ClimbTowerCellEvent();
                        cellEvent.setEventType(Integer.valueOf(eventConfig.get(0)));
                        if(cellEvent.getEventType() == eClimbTowerEventType.Division.getType() || cellEvent.getEventType() == eClimbTowerEventType.Treasures.getType()
                            || cellEvent.getEventType() == eClimbTowerEventType.Box.getType()){
                            cellEvent.setEventVal(eventConfig.get(1));
                        }else {
                            cellEvent.setEventVal(new BigDecimal(towerInfo.getAbility()).multiply(new BigDecimal(eventConfig.get(1))).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toString());
                        }
                        //本阶段最后一层
                        if(levelInfo.getBossId() > 0 && cellIdx == templateInfo.getEventList().size() - 1 && cellEvent.getEventType() == eClimbTowerEventType.Monster.getType()){
                            if(StringUtils.isNullOrEmpty(levelInfo.getReward()) || "0".equals(levelInfo.getReward())){
                                getLogger().info("ClimbTower Activity {} levelInfo {}  boss reward is empty", tmpActivityId, levelInfo.getId());
                                return;
                            }
                            cellEvent.setEventType(eClimbTowerEventType.Boss.getType());
                            cellEvent.setReward(levelInfo.getReward());
                            if(configTemp.getBossExParamList().size() > bossTimes) {
                                //血量重新计算
                                cellEvent.setEventVal(new BigDecimal(1000 + configTemp.getBossExParamList().get(bossTimes)).multiply(new BigDecimal(towerInfo.getAbility())).multiply(new BigDecimal(eventConfig.get(1))).divide(BigDecimal.valueOf(1000 * 1000), 0, BigDecimal.ROUND_UP).toString());
                            }
                            bossRewardTemps.add(ClimbTowerProto.ClimbTowerBossRewardTemp.newBuilder().setCellNum(cell.getCellNum()).setReward(levelInfo.getReward()).setBossId(levelInfo.getBossId()).build());
                        }
                        cellEvent.setPic(eventPicList.get(k));
                        cellEvent.setRawVal(Integer.valueOf(eventConfig.get(1)));
                        cell.getEventList().add(cellEvent);
                    }
                    levelInfo.getCellList().add(cell);
                }
            }

            configTemp.setLevelInfoList(levelInfoList);
            configTemp.setTemplateInfoList(templateInfoList);

            List<ClimbTowerRoleInfo> roleInfoList = ClimbTowerActivityBussiness.getRoleInfoList(tmpActivityId);
            configTemp.setRoleInfoList(roleInfoList);
            configTemp.setMultipleInfoList(ClimbTowerActivityBussiness.getMultipeInfoList(tmpActivityId));
            configTemp.setEventInfoList(ClimbTowerActivityBussiness.getEventInfoList(tmpActivityId));

            configTemp.setScoreItemId(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_ITEM_ID.getName()).getIntValue());
            configTemp.setAuraMax(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_AURA_MAX.getName()).getIntValue());
            configTemp.setAuraGetCd(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_AURA_GET_CD.getName()).getIntValue());
            configTemp.setAuraGetNum(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_AURA_GET_NUM.getName()).getIntValue());
            configTemp.setAuraCostNum(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_AURA_COST_NUM.getName()).getIntValue());
            configTemp.setPlayerStrengthBegin(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_PLAYER_STRENGTH_BEGIN.getName()).getIntValue());
            configTemp.setDrawScoreBase(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_DRAW_SCORE_BASE.getName()).getIntValue());
            configTemp.setDrawElementWeight(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_DRAW_ELEMENT_WEIGHT.getName()).getValue(), "\\|"));
            configTemp.setDrawSaveList(StringUtils.stringToStringList(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_DRAW_SAVE.getName()).getValue(), "\\|"));
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_ADD_AURA_ITEM_ID.getName())){
                configTemp.setAddAuraItemId(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_ADD_AURA_ITEM_ID.getName()).getIntValue());
            }
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_EXP_ITEM_ID.getName())){
                configTemp.setExpItemId(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_EXP_ITEM_ID.getName()).getIntValue());
            }
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_AURA_ITEM_ID.getName())){
                configTemp.setAuraItemId(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_AURA_ITEM_ID.getName()).getIntValue());
            }
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_STRENGTH_ITEM_ID.getName())){
                configTemp.setStrengthItemId(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_STRENGTH_ITEM_ID.getName()).getIntValue());
            }
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_DRAW_THREE_MULTIPLE.getName())){
                configTemp.setDrawThreeMultiple(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_DRAW_THREE_MULTIPLE.getName()).getIntValue());
            }
            if(activityConfigMap.containsKey(eActivityConfigType.EXCITINGTOWER_TOWER_MAX_FLOOR.getName())){
                configTemp.setTowerMaxFloor(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_TOWER_MAX_FLOOR.getName()).getIntValue());
            }
            configTemp.setArmsPicList(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_TOWER_ARMS_PIC.getName()).getValue(), "\\|"));
            configTemp.setGhostIdList(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_TOWER_GHOST_ID.getName()).getValue(), "\\|"));
            configTemp.setSkillUpnum(activityConfigMap.get(eActivityConfigType.EXCITINGTOWER_TOWER_SKILL_UPNUM.getName()).getIntValue());
            setBossRewardTempList(bossRewardTemps);
            config = configTemp;

            GamePlayerMgr.sendPacket(0, YanQuMessageUtils.buildMessage(Protocol.C_CLIMB_TOWER_TOP_UPDATE_END_TIME,
                    ClimbTowerProto.ClimbTowerCrossUpdateEndTimeReqMsg.newBuilder().setActivityId(config.getActivityInfo().getActivityId()).setEndShowTime(config.getActivityInfo().getEndShowTime())));
        }
        getLogger().info("reload ClimbTower Activity finish");

        // 在线玩家下发数据
        for (GamePlayer gamePlayer : GamePlayerMgr.getAllOnlinePlayer()) {
            ClimbTowerModule module = gamePlayer.getModule(ClimbTowerModule.class);
            module.syncConfig();
            module.initUserData();
            module.syncUserData();
        }
    }

    public static ClimbTowerCell getCell(int passId, int cell) {
        return config.getCell(passId, cell);
    }

    public static ClimbTowerCell getNextCell(int passId, int cell) {
        return config.getNextCell(passId, cell);
    }

    /**
     * 获取老虎机基础类型的盘面数据
     * @param type 类型
     * @param element 元素
     * @return 盘面数据
     *
     */
    public static int[] getBaseData(int type, int element){
        int[] result = initDrawData();
        if(type < 1 || type > 5){
            throw new RuntimeException();
        }
        for (int idx : getBaseTypeIdx(type)) {
            result[idx] = element;
        }
        return result;
    }

    /**
     * 0   1   2
     * 3   4   5
     * 6   7   8
     * @param type 线类型
     * @return 盘面下标
     */
    public static List<Integer> getBaseTypeIdx(int type){
        List<Integer> list = null;
        switch (type){
            case 1:
                list = StringUtils.stringToIntegerList("0,1,2", ",");
                break;
            case 2:
                list = StringUtils.stringToIntegerList("3,4,5", ",");
                break;
            case 3:
                list = StringUtils.stringToIntegerList("6,7,8", ",");
                break;
            case 4:
                list = StringUtils.stringToIntegerList("0,4,8", ",");
                break;
            case 5:
                list = StringUtils.stringToIntegerList("2,4,6", ",");
                break;
        }
        return list;
    }

    public static int[] randomNoComboElement(ClimbTowerConfig config, Random random) {
        int[] drawData = initDrawData();
        //游戏元素
        List<Integer> elements = config.getDrawElement();
        //按权重随机
        List<Integer> elementsWeight = config.getDrawElementWeight();
        for (int i = drawData.length - 1; i >= 0; i--) {
            List<Integer> poolList = new ArrayList<>(elements);
            int idx = RandomHelper.getRandomIndexByWeight(elementsWeight, random);
            drawData[i] = poolList.get(idx);
        }
        fillEmptyOrReplaceElement(drawData, config, false, random);
        return drawData;
    }

    public static int getRandomElement(ClimbTowerConfig config, List<Integer> excludeList, Random random, ClimbTowerMultipleInfo multipleInfo){
        //游戏元素
        List<Integer> elements = new ArrayList<>();
        //按权重随机
        List<Integer> elementsWeight = new ArrayList<>();
        for (String eleWeightStr : multipleInfo.getElementWeightList()) {
            List<Integer> list = StringUtils.stringToIntegerList(eleWeightStr, ";");
            elements.add(list.get(0));
            elementsWeight.add(list.get(1));
        }
        List<Integer> poolList = new ArrayList<>(elements);
        List<Integer> weightList = new ArrayList<>(elementsWeight);
        excludeElementWithWeight(excludeList, poolList, weightList);
        if(poolList.size() > 0){
            int idx = RandomHelper.getRandomIndexByWeight(weightList, random);
            return poolList.get(idx);
        }
        return 0;
    }

    private static void excludeElementWithWeight(Collection<Integer> excludeList, List<Integer> poolList, List<Integer> weight) {
        for (int ele : excludeList) {
            int idx = poolList.indexOf(ele);
            poolList.remove(idx);
            weight.remove(idx);
        }
    }

    /**
     * 填满空位置或者替换元素
     * @param drawData  固定长度一定是9
     * 0   1   2
     * 3   4   5
     * 6   7   8
     * @param config  配置
     * @param onlyEmpty 是否只替换空位置
     */
    public static void fillEmptyOrReplaceElement(int[] drawData, ClimbTowerConfig config, boolean onlyEmpty, Random random) {
        //游戏元素
        List<Integer> elements = config.getDrawElement();
        //游戏元素权重
        List<Integer> elementsWeight = config.getDrawElementWeight();

        //填充空位置
        for (int i = 0; i < drawData.length; i++) {
            if(onlyEmpty && drawData[i] != 0){
                continue;
            }
            Set<Integer> excludeElement = ClimbTowerMgr.calExcludeElement(drawData, i);
            List<Integer> poolList = new ArrayList<>(elements);
            List<Integer> weight = new ArrayList<>(elementsWeight);
            excludeElementWithWeight(excludeElement, poolList, weight);
            if(poolList.size() > 0){
                int idx = RandomHelper.getRandomIndexByWeight(weight, random);
                drawData[i] = poolList.get(idx);
            }
        }
    }

    /**
     * 0   1   2
     * 3   4   5
     * 6   7   8
     * @return 盘面数据
     */
    public static int[] initDrawData() {
        int[] result = new int[DRAW_ELEMENT_NUM];
        for (int i = 0; i < DRAW_ELEMENT_NUM; i++) {
            result[i] = 0;
        }
        return result;
    }

    /**
     * 遍历基本类型，排除不可出现的元素
     * @param drawData
     * 0   1   2
     * 3   4   5
     * 6   7   8
     * @param i 下标
     * @return 排查的数据
     */
    public static Set<Integer> calExcludeElement(int[] drawData, int i) {
        Set<Integer> result = new HashSet<>();
        List<String> typeIndexList = StringUtils.stringToStringList("0,1,2;3,4,5;6,7,8;0,4,8;2,4,6", ";");
        for (String typeIndex : typeIndexList) {
            List<Integer> indexList = StringUtils.stringToIntegerList(typeIndex, ",");
            if(indexList.contains(i)){
                Map<Integer, Integer> countMap = new HashMap<>();
                for (int k = 0; k < indexList.size(); k++) {
                    int index = indexList.get(k);
                    if(drawData[index] != 0){
                        int count = countMap.getOrDefault(drawData[index], 0);
                        countMap.put(drawData[index], count + 1);
                    }
                }
                for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
                    if(entry.getValue() > 1){
                        result.add(entry.getKey());
                    }
                }
            }
        }
        return result;
    }

    public static boolean isSpecialGoods(int goodsId) {
        if(config == null){
            return false;
        }
        int[] goodsIdList = new int[]{ config.getAuraItemId(), config.getExpItemId(), config.getStrengthItemId()};
        for (int id : goodsIdList) {
            if(id == goodsId){
                return true;
            }
        }
        return false;
    }

    public static BigDecimal trim(BigDecimal srcVal){
        List<BigDecimal> beiShuList = new ArrayList<>();
        beiShuList.add(BigDecimal.valueOf(10000));
        beiShuList.add(BigDecimal.valueOf(10000 * 10000));
        beiShuList.add(new BigDecimal("1000000000000"));
        for (int i = beiShuList.size() - 1; i >= 0; i--) {
            if(srcVal.compareTo(beiShuList.get(i)) >= 0){
                return srcVal.divide(beiShuList.get(i), 3, BigDecimal.ROUND_UP).multiply(beiShuList.get(i));
            }
        }
        return srcVal;
    }


    public static ClimbTowerConfig getConfig() {
        return config;
    }

    public static void setConfig(ClimbTowerConfig config) {
        ClimbTowerMgr.config = config;
    }

    public static List<ClimbTowerProto.ClimbTowerBossRewardTemp> getBossRewardTempList() {
        return bossRewardTempList;
    }

    public static void setBossRewardTempList(List<ClimbTowerProto.ClimbTowerBossRewardTemp> bossRewardTempList) {
        ClimbTowerMgr.bossRewardTempList = bossRewardTempList;
    }

    public static int getActivityId(){
        if(getActivityInfo() == null){
            return 0;
        }
        return getActivityInfo().getActivityId();
    }
}
